// CrashHandler.cpp: implementation of the CCrashHandler class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "CrashHandler.h"

#include <stdio.h>
#ifdef _DEBUG
	#pragma comment(exestr, "*** DEBUG file detected, Last Compiled: " __DATE__ ", " __TIME__ " ***")
#else if _FINIAL
	#pragma comment(exestr, "*** FINIAL file detected, Last Compiled: " __DATE__ ", " __TIME__ " ***")
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

#define SIZE_TEMP				0x200

static char s_szCompiledDate[] = __DATE__;
static char s_szCompiledTime[] = __TIME__;

static int						s_nNumAddress = 0;
static DWORD					s_pAddress[30];
static EXCEPTION_POINTERS		s_sExPtrs;
//static BYTE						s_pStackMemory[SIZE_TEMP];
static BYTE*					s_pStackMemory;

//
static bool						s_bGetMemory	= false;
static bool						s_bShowed		= false;




CCrashHandler*	CCrashHandler::m_pThis = NULL;


CCrashHandler::CCrashHandler()
{
	if( m_pThis == NULL )
	{
		m_pThis = this;
	}

}

CCrashHandler::~CCrashHandler()
{

}

BOOL CCrashHandler::Init()
{
	GetCurrentDirectory(MAX_PATH, m_szPath);
	//wsprintf(m_szPath, L"%s\\EventLog", m_szPath);
	sprintf(m_szPath, "%s\\EventLog", m_szPath);

//	SetUnhandledExceptionFilter(CrashHandlerExceptionFilter);


	return TRUE;

}

void CCrashHandler::Release()
{

}

void CCrashHandler::Exit(char* szErrMsg)
{
	if( !s_bShowed )
	{
		s_bShowed = true;
		_CrashHandler()->Report(szErrMsg);
	}

}

static	DWORD		s_dwCode;
static	DWORD		s_dwStack;
static	DWORD*		s_pStack;

LONG CCrashHandler::ExceptionCallBack(EXCEPTION_POINTERS *pExPtrs)
{
	if( !s_bGetMemory )
	{
		s_bGetMemory		= true;

		s_dwCode		= pExPtrs->ContextRecord->Eip;
		s_dwStack		= pExPtrs->ContextRecord->Ebp;
		s_pStack		= (DWORD*)s_dwStack;

		// Error Infomaition & Register Memory Infomaition 
		s_sExPtrs = *pExPtrs;

		// Stack Memory Information
		s_pStackMemory = new BYTE[SIZE_TEMP];
		memcpy(s_pStackMemory, (BYTE*)pExPtrs->ContextRecord->Esp, SIZE_TEMP);

		// Call Stack Information
		s_pAddress[s_nNumAddress] = s_dwCode;
		++s_nNumAddress;

		while( s_pStack && (unsigned long)s_pStack != 0xffffffff && s_dwCode && s_nNumAddress < 30 )
		{
			if( (DWORD)s_pStack > 0x80000000 )
			{
				break;
			}
			s_dwStack	= *s_pStack;
			s_pStack	+= 1;
			s_dwCode	= *s_pStack;

			s_pStack	= (DWORD*)s_dwStack;

			s_pAddress[s_nNumAddress] = s_dwCode;
			++s_nNumAddress;
		}
	}
	if( !s_bShowed )
	{
		s_bShowed = true;
		_CrashHandler()->Report("Error");
		
	}
	

	SAFEDELETE(s_pStackMemory);
	return EXCEPTION_EXECUTE_HANDLER;

}


void CCrashHandler::Report(char* szErrMsg)
{
	char			szFileName[64];
	SYSTEMTIME		sSysTime;


	if( !SetCurrentDirectory(m_szPath) )
	{
		CreateDirectory(m_szPath, NULL);
		SetCurrentDirectory(m_szPath);
	}

	GetLocalTime(&sSysTime);
	sprintf(szFileName, "BugReport_%d%d_%d%d.log", sSysTime.wMonth, sSysTime.wDay, sSysTime.wHour, sSysTime.wMinute);

	m_pFile = fopen(szFileName, "wt");

	//fprintf(m_pFile, STR_2006);
	// Time
	ReportTime(sSysTime);
	// Last Compiled
	ReportLastCompiled();
	// ErrMsg
	ReportErrMsg(szErrMsg);

	// Crash
	ReportCrash();

	fclose(m_pFile);

	// Create NotePad
	char szNotepad[MAX_PATH];
	sprintf(szNotepad, "Notepad.exe %s", szFileName);
	WinExec(szNotepad, SW_SHOWNORMAL);

}

void CCrashHandler::ReportCrash()
{
	if( !s_nNumAddress )
	{
		return;
	}

	// Error Infomaition 
	fprintf(m_pFile, "[ Error Infomaition ] \n");
	fprintf(m_pFile, "Error Code : %X \n", s_sExPtrs.ExceptionRecord->ExceptionCode);
	fprintf(m_pFile, "\n");

	// Call Stack Information
	fprintf(m_pFile, "[ Call Stack Information ] \n");
	int  i =0;
	for(i = 0; i < s_nNumAddress; ++i)
	{
		fprintf(m_pFile, "0001 : 0x%08x \n", s_pAddress[i]);
	}
	fprintf(m_pFile, "\n");

	// Register Memory Infomaition 
	fprintf(m_pFile, "[ Register Memory Infomaition ] \n");
	fprintf(m_pFile, "EAX : 0x%08X \n", s_sExPtrs.ContextRecord->Eax);
	fprintf(m_pFile, "EBX : 0x%08X \n", s_sExPtrs.ContextRecord->Ebx);
	fprintf(m_pFile, "ECX : 0x%08X \n", s_sExPtrs.ContextRecord->Ecx);
	fprintf(m_pFile, "EDX : 0x%08X \n", s_sExPtrs.ContextRecord->Edx);
	fprintf(m_pFile, "ESI : 0x%08X \n", s_sExPtrs.ContextRecord->Esi);
	fprintf(m_pFile, "EDI : 0x%08X \n", s_sExPtrs.ContextRecord->Edi);
	fprintf(m_pFile, "EIP : 0x%08X \n", s_sExPtrs.ContextRecord->Eip);
	fprintf(m_pFile, "ESP : 0x%08X \n", s_sExPtrs.ContextRecord->Esp);
	fprintf(m_pFile, "EBP : 0x%08X \n", s_sExPtrs.ContextRecord->Ebp);
	fprintf(m_pFile, "Flg : 0x%08X \n", s_sExPtrs.ContextRecord->EFlags);
	fprintf(m_pFile, "CS  : 0x%08X \n", s_sExPtrs.ContextRecord->SegCs);
	fprintf(m_pFile, "DS  : 0x%08X \n", s_sExPtrs.ContextRecord->SegDs);
	fprintf(m_pFile, "SS  : 0x%08X \n", s_sExPtrs.ContextRecord->SegSs);
	fprintf(m_pFile, "ES  : 0x%08X \n", s_sExPtrs.ContextRecord->SegEs);
	fprintf(m_pFile, "FS  : 0x%08X \n", s_sExPtrs.ContextRecord->SegFs);
	fprintf(m_pFile, "GS  : 0x%08X \n", s_sExPtrs.ContextRecord->SegGs);
	fprintf(m_pFile, "\n");
	// Stack Memory Information
	fprintf(m_pFile, "[ Stack Memory Infomaition ]");
	DWORD	dwSp = s_sExPtrs.ContextRecord->Esp;
	for(i = 0; i < SIZE_TEMP; ++i)
	{
		if( (i % 16) == 0 )
		{
			fprintf(m_pFile, "\n");
			fprintf(m_pFile, "0x%08X\t", dwSp + i);
		}
		fprintf(m_pFile, "%02X ", s_pStackMemory[i]);
	}
	fprintf(m_pFile, "\n");
	fprintf(m_pFile, "\n");
	

}

void CCrashHandler::ReportTime(SYSTEMTIME &sSysTime)
{
	fprintf(m_pFile, "%d-%d-%d ", sSysTime.wYear, sSysTime.wMonth, sSysTime.wDay);
	fprintf(m_pFile, "%d:%d:%d ", sSysTime.wHour, sSysTime.wMinute, sSysTime.wSecond);

}

void CCrashHandler::ReportLastCompiled()
{
	fprintf(m_pFile, "Last Compiled :\t\t%s, %s \n", s_szCompiledDate, s_szCompiledTime);

}

// End
void CCrashHandler::ReportErrMsg(char *szErrMsg)
{
	if( szErrMsg )
	{
		fprintf(m_pFile, "\n");
		fprintf(m_pFile, "[ Error Message ] \n");
		fprintf(m_pFile, szErrMsg);
		fprintf(m_pFile, "\n");
	}
	fprintf(m_pFile, "\n");

}

